/**
 * Copyright (c) 2010-2020 by skzr.org
 * All rights reserved.
 * @Author skzr.org(E-mail:skzr.org@gmail.com)
 * @date 2010-4-26 下午09:56:26
 */
package org.skzr.proxy;

import java.io.DataInputStream;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.Enumeration;
import java.util.Properties;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.mortbay.jetty.Handler;
import org.mortbay.jetty.Request;
import org.mortbay.jetty.Server;
import org.mortbay.jetty.handler.AbstractHandler;
import org.skzr.framework.util.UtilIO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @jdk 1.6
 * @author skzr.org(E-mail:skzr.org@gmail.com)
 * @version 1.0.0
 */
public class ProxyJettyServer {
	protected final transient Logger logger = LoggerFactory.getLogger(getClass());
	private int port = 8080;
	private String fetchUrl;
	private Server server;
	
	public ProxyJettyServer(String fetchUrl, int port) {
		this.fetchUrl = fetchUrl;
		this.port = port;
	}

	public void start() throws Exception {
		logger.info("ProxyJettyServer 启动...");
		logger.info("监听端口： {}, 远端提取地址： {}", port, fetchUrl);
		server = new Server(port);
		server.setHandler(new ProxyServletHandler(fetchUrl));
		server.start();
	}
	
	public static void main(String[] args) throws Exception {
		URL initUrl = null;
		for (Enumeration<URL> iter = Thread.currentThread().getContextClassLoader().getResources("init.properties"); iter.hasMoreElements();) {
			URL u = iter.nextElement();
			if (u.toString().startsWith("file")) {
				initUrl = u;
			}
		}
		if (initUrl == null) {
			initUrl = Thread.currentThread().getContextClassLoader().getResource("init.properties");
		}
		Properties prop = new Properties();
		prop.load(initUrl.openStream());
		
		String fetchUrl = prop.getProperty("fetchUrl", "http://localhost:8888/fetch").trim();
		if (fetchUrl.isEmpty()) throw new IllegalArgumentException("init.properties配置项[fetchUrl]错误");
		String portStr = prop.getProperty("port", "8080").trim();
		if (portStr.isEmpty()) throw new IllegalArgumentException("init.properties配置项[port]错误");
		new ProxyJettyServer(fetchUrl, Integer.parseInt(portStr, 10)).start();
	}
}

class ProxyServletHandler extends AbstractHandler implements Handler {
	protected final transient Logger logger = LoggerFactory.getLogger(getClass());
	private ThreadLocal<DefaultHttpClient> clientThead = new ThreadLocal<DefaultHttpClient>();
	private String fetchUrl;
	private URI fetchUri;
	
	public ProxyServletHandler(String fetchUrl) {
		this.fetchUrl = fetchUrl;
	}

	private DefaultHttpClient getClient() {
		DefaultHttpClient client = clientThead.get();
		if (client == null) {
			client = new DefaultHttpClient();
			clientThead.set(client);
		}
		return client;
	}

	private URI getProxyUri() {
		if (fetchUri == null) {
			try {
				fetchUri = new URI(fetchUrl);
			} catch (URISyntaxException e) {
				logger.warn("网络问题", e);
			}
		}
		return fetchUri;
	}
	
	@SuppressWarnings({ "unchecked", "deprecation" })
	@Override
	public void handle(String target, HttpServletRequest request, HttpServletResponse response, int dispatch) throws IOException, ServletException {
		logger.debug("target: {}, dispatch: {}", target, dispatch);
		ProxyEntity entity = new ProxyEntity();
		{//处理rawurl
			String method = request.getMethod(), protocol = request.getProtocol();
			if (method != null) method = method.toUpperCase();
			String query = request.getQueryString();
			String uri = (query != null && !query.isEmpty()) ? 
					request.getRequestURL() + "?" + query : 
						request.getRequestURL().toString();
			logger.debug("[proxy][req]{} {} {}", new Object[]{method, uri, protocol});
			entity.setRawUrl(method, uri, protocol);
		} {//处理头
			String name, value;
			for (Enumeration<String> iter = request.getHeaderNames(); iter.hasMoreElements();) {
				name = iter.nextElement();
				if (!name.toLowerCase().equals("proxy-connection")) {
					for (Enumeration<String> iter2 = request.getHeaders(name); iter2.hasMoreElements();) {
						value = iter2.nextElement();
						logger.trace("[proxy][req][header] {}: {}", name, value);
						entity.addHeader(name, value);
					}
				}
			}
		}
		entity.setBody(request.getInputStream());
		
		HttpPost post = new HttpPost(getProxyUri());
		post.setEntity(entity);
		HttpResponse gaeResponse = getClient().execute(post);
//		httpVersion,responseCode,codeStr,header.size(),headers,content
		DataInputStream din = null;
		try {
			HttpEntity tmp = gaeResponse.getEntity();
			din = new DataInputStream(tmp.getContent());
			String protocol = din.readUTF();
			int code = din.readInt();
			String msg = din.readUTF();
			logger.trace("[proxy][out] {} {} {}", new Object[]{protocol, code, msg});
			String name, value;
			for (int i = 0, len = din.readInt(); i < len; i++) {
				name = din.readUTF();
				value = din.readUTF();
				logger.trace("[proxy][out][header] {}: {}", name, value);
				response.addHeader(name, value);
			}
			logger.trace("[proxy][out] 开始发送:{} {}", code, msg);
			response.setStatus(code, msg);
			UtilIO.write(din, response.getOutputStream());
			logger.trace("[proxy][out] 发送完成");
		} catch (Exception e) {
			logger.warn("[开发者][未实现] 需要实现此逻辑[发生异常]", e);
		} finally {
			UtilIO.close(din);
			post.abort();
		}
        ((Request)request).setHandled(true);
	}
}